#include "codec.h"
#include "dispatcher.h"
#include"dict.pb.h"

#include "muduo/base/Logging.h"
#include "muduo/base/Mutex.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpServer.h"

#include <stdio.h>
#include <unistd.h>

using namespace muduo;
using namespace muduo::net;

// typedef std::shared_ptr<muduo::Query> QueryPtr;
// typedef std::shared_ptr<muduo::Answer> AnswerPtr;


typedef std::shared_ptr<dict::AddRequest> Addreqptr;
typedef std::shared_ptr<dict::AddResponse> Addrespsptr;

typedef std::shared_ptr<dict::TransRequest> Transreqptr;
typedef std::shared_ptr<dict::TransResponse> Transrespptr;


class QueryServer : noncopyable
{
 public:
  QueryServer(const InetAddress& listenAddr)
  : server_(&loop_, listenAddr, "QueryServer"),
    dispatcher_(std::bind(&QueryServer::onUnknownMessage, this, _1, _2, _3)),
    codec_(std::bind(&ProtobufDispatcher::onProtobufMessage, &dispatcher_, _1, _2, _3))
  {
    dispatcher_.registerMessageCallback<dict::AddRequest>(
        std::bind(&QueryServer::onAddRequst, this, _1, _2, _3));
    dispatcher_.registerMessageCallback<dict::TransRequest>(
        std::bind(&QueryServer::onTranslateRequst, this, _1, _2, _3));

    // dispatcher_.registerMessageCallback<dict::AddResponse>(
    //     std::bind(&QueryServer::onAddRespons, this, _1, _2, _3));
    // dispatcher_.registerMessageCallback<dict::TransResponse>(
    //     std::bind(&QueryServer::onTranslateRespons, this, _1, _2, _3));

    server_.setConnectionCallback(
        std::bind(&QueryServer::onConnection, this, _1));
        //绑定codec的Message
    server_.setMessageCallback(
        std::bind(&ProtobufCodec::onMessage, &codec_, _1, _2, _3));
  }

  void start()
  {
    server_.start();
    loop_.loop();
  }

 private:
  void onConnection(const TcpConnectionPtr& conn)
  {
    LOG_INFO << conn->peerAddress().toIpPort() << " -> "
        << conn->localAddress().toIpPort() << " is "
        << (conn->connected() ? "UP" : "DOWN");
  }

  void onUnknownMessage(const TcpConnectionPtr& conn,
                        const MessagePtr& message,
                        Timestamp)
  {
    LOG_INFO << "onUnknownMessage: " << message->GetTypeName();
    conn->shutdown();
  }

  void onAddRequst(const muduo::net::TcpConnectionPtr& conn,
               const Addreqptr& message,
               muduo::Timestamp){
              int num1 =  message->num1();
              int num2 = message->num2();
              int sum = num1 + num2;

              dict::AddResponse msg;
              msg.set_num(sum);
              codec_.send(conn,msg);

              // conn->shutdown();
  }


  std::string TranslateHelper(const std::string& word){
      std::unordered_map<std::string,std::string> transmap{
                {"hello","你好"},{"Hello","你好"},{"speak","说"}
            };
            auto pos = transmap.find(word);
            if(pos == transmap.end()){
                std::cout<<"find nothing"<<std::endl;
                return "没找到。。。";
            }
            return pos->second;
  }

  void onTranslateRequst(const muduo::net::TcpConnectionPtr& conn,
               const Transreqptr& message,
               muduo::Timestamp){
              std::string word = message->msg();
              std::string translation = TranslateHelper(word);

              std::cout<<"hava a translation\n";
              dict::TransResponse trans;
              trans.set_msg(translation);
              codec_.send(conn,trans);
              
              // conn->shutdown();
  }  

    // void onAddRespons(const muduo::net::TcpConnectionPtr& conn,
  //              const Addresp& message,
  //              muduo::Timestamp){

  // }  

  // void onTranslateRespons(const muduo::net::TcpConnectionPtr& conn,
  //              const Transresp& message,
  //              muduo::Timestamp){

  // }

  // void onQuery(const muduo::net::TcpConnectionPtr& conn,
  //              const QueryPtr& message,
  //              muduo::Timestamp)
  // {
  //   LOG_INFO << "onQuery:\n" << message->GetTypeName() << message->DebugString();
  //   Answer answer;
  //   answer.set_id(1);
  //   answer.set_questioner("Chen Shuo");
  //   answer.set_answerer("blog.csdn.net/Solstice");
  //   answer.add_solution("Jump!");
  //   answer.add_solution("Win!");
  //   codec_.send(conn, answer);

  //   conn->shutdown();
  // }

  // void onAnswer(const muduo::net::TcpConnectionPtr& conn,
  //               const AnswerPtr& message,
  //               muduo::Timestamp)
  // {
  //   LOG_INFO << "onAnswer: " << message->GetTypeName();
  //   conn->shutdown();
  // }

  TcpServer server_;
  ProtobufDispatcher dispatcher_;
  ProtobufCodec codec_;
  EventLoop loop_;
};

int main(int argc, char* argv[])
{
  LOG_INFO << "pid = " << getpid();
  if (argc > 1)
  {
    
    uint16_t port = static_cast<uint16_t>(atoi(argv[1]));
    InetAddress serverAddr(port);
    QueryServer server(serverAddr);
    server.start();
    // loop.loop();
  }
  else
  {
    printf("Usage: %s port\n", argv[0]);
  }
}

